package com.sh.rpc.protocol;

import com.sh.rpc.model.RpcRequest;
import com.sh.rpc.model.RpcResponse;
import com.sh.rpc.serializer.Serializer;
import com.sh.rpc.serializer.SerializerFactory;
import io.vertx.core.buffer.Buffer;

/**
 * 解码器
 * @author sh
 */
public class protocolMessageDecoder {

    /**
     * 解码
     */
    public static ProtocolMessage<?> decode(Buffer buffer) throws Exception {
        ProtocolMessage.Header header = new ProtocolMessage.Header();  // 创建一个协议消息头
        byte magic = buffer.getByte(0);  // 获取魔数
        // 判断魔数是否正确
        if (magic != ProtocolConstant.PROTOCOL_MAGIC) {
            throw new IllegalArgumentException("消息魔术值非法: " + magic);
        }
        header.setMagic(magic);  // 设置魔数
        header.setVersion(buffer.getByte(1));  // 获取版本号
        header.setSerializer(buffer.getByte(2));  // 获取序列化方式
        header.setType(buffer.getByte(3));  // 获取消息类型
        header.setStatus(buffer.getByte(4));  // 获取状态
        header.setRequestId(buffer.getLong(5));  // 获取请求ID   从第5个字节开始读取8个字节
        header.setBodyLength(buffer.getInt(13));  // 获取消息体长度  从第13个字节开始读取4个字节
        // 解决粘包问题, 从17开始读取消息体
        byte[] bodyBytes = buffer.getBytes(17, 17 + header.getBodyLength());
        // 解析消息体
        ProtocolMessageSerializerEnum serializerEnum = ProtocolMessageSerializerEnum.getEnumByKey(header.getSerializer());
        if ( serializerEnum==null){
            throw new RuntimeException("解码器不支持的序列化方式: " + header.getSerializer());
        }
        Serializer serializer = SerializerFactory.getInstance(serializerEnum.getValue());
        ProtocolMessageTypeEnum messageTypeEnum = ProtocolMessageTypeEnum.getEnumByKey(header.getType());
        if (messageTypeEnum == null){
            throw new RuntimeException("解码器不支持的消息类型: " + header.getType());
        }
        switch(messageTypeEnum){
            case REQUEST:
                RpcRequest request = serializer.deserialize(bodyBytes, RpcRequest.class);
                return new ProtocolMessage<>(header, request);
            case RESPONSE:
                RpcResponse response = serializer.deserialize(bodyBytes, RpcResponse.class);
            case HEART_BEAT:
            case OTHERS:
            default:
                throw new RuntimeException("解码器不支持的消息类型: " + header.getType());
        }

    }

}
